#include <core/common/global.h>
#include <core/common/system.h>
#include <core/common/string.h>
#include <core/common/file.h>
#include <core/common/log.h>

#ifdef OS_PLATFORM_LINUX
	#include <sys/utsname.h>
	#include <sys/wait.h>
#ifndef ANDROID
	#include <shadow.h>
#endif
	#include <unistd.h>
	#include <malloc.h>
	#include <sys/ioctl.h>
	#include <sys/sysinfo.h>
	#include <sys/statfs.h>
	#include <sys/statvfs.h>
	#include <sys/reboot.h>
	#include <sys/vfs.h>
	#include <net/route.h>
	#include <linux/reboot.h>
#else
	#include <winioctl.h>
	#include <shellapi.h>
	#include <tlhelp32.h>
	#include <psapi.h>
	#include <winternl.h>
	#include <winnls.h>
	#include <windows.h> 
	#include <lm.h>
#endif

#ifdef ANDROID
__BEGIN_DECLS
extern int sysinfo (struct sysinfo *info);
__END_DECLS

#endif

#ifdef OS_PLATFORM_WINDOWS
HANDLE ___winGetActivatedUserProcessToken()
{
	HANDLE processToken = NULL;
	HANDLE explorerProcess = NULL;
	DWORD consoleSessionId = WTSGetActiveConsoleSessionId();
	DWORD explorerProcessId = (DWORD)-1;
	core::common::ProcessList list;
	core::common::System::getProcessList(list);

	for( core::common::ProcessList::iterator itr = list.begin(); itr != list.end(); itr ++ )
	{
		core::common::Process &item = (*itr);
		std::string name = core::common::File::getNameFromPath(item.binaryPath_);
		if( core::common::String::compareTo(name.c_str(), "explorer.exe", true) != 0 )
		{
			continue;
		}

		DWORD sessionId = (DWORD)-1;
		if( !ProcessIdToSessionId(item.id_, &sessionId) )
		{
			continue;
		}
		if( sessionId == consoleSessionId )
		{
			explorerProcessId = item.id_;
			break;
		}
		else if( explorerProcessId == (DWORD)-1 )
		{
			explorerProcessId = item.id_;
		}
	}

	do 
	{
		if( explorerProcessId == (DWORD)-1 )
		{
			break;
		}

		explorerProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, explorerProcessId);
		if( NULL == explorerProcess )
		{
			__ULOG_ERROR(__ULOG_FMT_ERR("common::System", "Open explorer process failed"), __UERR_CODE, __UERR_STR);
			break;
		}
		if( !OpenProcessToken(explorerProcess, TOKEN_ALL_ACCESS, &processToken) )
		{
			__ULOG_ERROR(__ULOG_FMT_ERR("common::System", "Open explorer token failed"), __UERR_CODE, __UERR_STR);
			break;
		}
	} while (false);

	if( NULL != explorerProcess )
	{
		CloseHandle(explorerProcess);
		explorerProcess = NULL;
	}
	
	return processToken;
}
#endif

//
// class common::Process
//
uint32 core::common::Process::create( const std::string &file, 
							  const core::common::StringList &parameters,
							  bool  appendStdFile,
							  const std::string &stdoutFile,
							  const std::string &stderrFile,
							  bool showWindow,
							  bool shellExecute,
							  int waitMilliSeconds,
							  const std::string &workingPath,
							  bool plainParameters,
							  bool createAsActivatedUser )
{
	std::string normalFile = core::common::File::normalizePathTo(file);
	std::string normalWorkingPath = core::common::File::normalizePathTo(workingPath);
	std::string normalOutFile = core::common::File::normalizePathTo(stdoutFile);
	std::string normalErrFile = core::common::File::normalizePathTo(stderrFile);

#ifdef OS_PLATFORM_WINDOWS
	std::string parameterString;
	LPCSTR currentDirectory = normalWorkingPath.empty() ? NULL : normalWorkingPath.c_str();

	for( core::common::StringList::const_iterator itr = parameters.begin(); itr != parameters.end(); itr ++ )
	{
		std::string arg = (* itr);
		if( arg.size() > 0 )
		{
			if( arg[0] == '-' || arg[0] == '/' )
			{
				core::common::String::appendFormat(parameterString, " %s", arg.c_str());
				continue;
			}
			else if( arg[0] == '|' )
			{
				std::string strSubArg = arg.substr(1);
				core::common::String::appendFormat(parameterString, " %s", strSubArg.c_str());
				continue;
			}
		}
		if( !plainParameters )
		{
			core::common::String::replace(arg, "\\", "\\\\");
			core::common::String::replace(arg, "\"", "\\\"");
		}
		core::common::String::appendFormat(parameterString, " \"%s\"", arg.c_str());
	}

	if( shellExecute )
	{
		int instance = (int)ShellExecuteA(NULL, "open", normalFile.c_str(), parameterString.c_str(), currentDirectory, showWindow ? SW_SHOWNORMAL : SW_HIDE);
		return instance > 32 ? 0 : core::common::Process::kInvalidId;
	}

	STARTUPINFO startupInfo;
	PROCESS_INFORMATION processInfo;
	SECURITY_ATTRIBUTES securityAttributes;

	ZeroMemory(&startupInfo, sizeof(startupInfo));
	ZeroMemory(&processInfo, sizeof(processInfo));
	ZeroMemory(&securityAttributes, sizeof(securityAttributes));

	startupInfo.cb = sizeof(startupInfo);
	startupInfo.dwFlags = STARTF_USESHOWWINDOW;
	startupInfo.wShowWindow = showWindow ? SW_SHOWNORMAL : SW_HIDE;

	securityAttributes.nLength = sizeof(securityAttributes);
	securityAttributes.bInheritHandle = TRUE;

	std::string command = core::common::String::format("\"%s\"", normalFile.c_str());
	if( !parameterString.empty() )
	{
		core::common::String::appendFormat(command, " %s", parameterString.c_str());
	}

	bool appendUsed = false;
	HANDLE newStdoutFile = INVALID_HANDLE_VALUE;
	HANDLE newStderrFile = INVALID_HANDLE_VALUE;
	HANDLE processToken = NULL;

	if( normalOutFile.size() > 0 )
	{
		startupInfo.dwFlags |= STARTF_USESTDHANDLES;

		DWORD createFlags = appendStdFile ? OPEN_ALWAYS : CREATE_ALWAYS;
		newStdoutFile = CreateFileA(normalOutFile.c_str(),
			GENERIC_READ|GENERIC_WRITE,
			FILE_SHARE_READ|FILE_SHARE_WRITE, 
			&securityAttributes,
			createFlags,
			FILE_ATTRIBUTE_NORMAL, 
			NULL);
		if( INVALID_HANDLE_VALUE == newStdoutFile )
		{
			__ULOG_ERROR(__ULOG_FMT("common::System", "CreateProcess open out file failed(%s)"), normalOutFile.c_str(), __UERR_CODE, __UERR_STR);
			return false;
		}

		startupInfo.hStdOutput = newStdoutFile;
		if( normalErrFile == normalOutFile )
		{
			appendUsed = true;
			startupInfo.hStdError = newStdoutFile;
		}
	}
	
	if( normalErrFile.size() > 0 && !appendUsed )
	{
		startupInfo.dwFlags |= STARTF_USESTDHANDLES;

		DWORD createFlags = appendStdFile ? OPEN_ALWAYS : CREATE_ALWAYS;
		newStderrFile = CreateFileA(normalErrFile.c_str(), 
			GENERIC_READ|GENERIC_WRITE,
			FILE_SHARE_READ|FILE_SHARE_WRITE,
			&securityAttributes,
			createFlags, 
			FILE_ATTRIBUTE_NORMAL,
			NULL);
		if( INVALID_HANDLE_VALUE == newStderrFile )
		{
			__ULOG_ERROR(__ULOG_FMT("common::System", "CreateProcess open error file failed(%s)"), normalErrFile.c_str(), __UERR_CODE, __UERR_STR);
			return false;
		}

		startupInfo.hStdError = newStderrFile;
	}

	if( createAsActivatedUser )
	{
		processToken = ___winGetActivatedUserProcessToken();
		if( NULL == processToken )
		{
			__ULOG_WARNING(__ULOG_FMT("common::System", "CreateProcess as activated user failed, process token not found, create as normal instead"));
		}
	}

	if( NULL == startupInfo.hStdOutput )
	{
		startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	}

	if( NULL == startupInfo.hStdError )
	{
		startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
	}

	BOOL created = FALSE;
	if( NULL != processToken )
	{
		created = CreateProcessAsUserA(processToken, NULL, (LPSTR)command.c_str(), NULL, NULL, TRUE, 0, NULL, currentDirectory, &startupInfo, &processInfo);
	}
	else
	{
		created = CreateProcessA(NULL, (LPSTR)command.c_str(), NULL, NULL, TRUE, 0, NULL, currentDirectory, &startupInfo, &processInfo);
	}

	uint32 backupError = core::common::getErrorCode();
	if( created )
	{
		if( waitMilliSeconds != 0 )
		{
			DWORD millis = waitMilliSeconds > 0 ? (DWORD)waitMilliSeconds : INFINITE;
			WaitForSingleObject(processInfo.hProcess, millis);
		}
		CloseHandle(processInfo.hProcess);
		CloseHandle(processInfo.hThread);
	}

	if( INVALID_HANDLE_VALUE != newStdoutFile )
	{
		CloseHandle(newStdoutFile);
		newStdoutFile = INVALID_HANDLE_VALUE;
	}

	if( INVALID_HANDLE_VALUE != newStderrFile )
	{
		CloseHandle(newStderrFile);
		newStderrFile = INVALID_HANDLE_VALUE;
	}

	if( NULL != processToken )
	{
		CloseHandle(processToken);
		processToken = NULL;
	}

	core::common::setErrorCode(backupError);
	return processInfo.dwProcessId;
#else
	char **commandArgs  = new char *[parameters.size() + 2];
	commandArgs[0] = (char *)file.c_str();
	commandArgs[parameters.size() + 1] = NULL;

	size_t argIndex = 1;
	for( core::common::StringList::const_iterator itr = parameters.begin(); itr != parameters.end(); itr ++, argIndex ++ )
	{
		const std::string &parameter = (*itr);
		commandArgs[argIndex] = (char *)parameter.c_str();
	}

	int processId = fork();
	if( processId < 0 )
	{
		delete []commandArgs;
		commandArgs = NULL;
		return core::common::Process::kInvalidId;
	}
	else if( 0 == processId )
	{
		bool appendUsed = false;
		int  createFlags = appendStdFile ? O_WRONLY|O_CREAT : O_WRONLY|O_CREAT|O_TRUNC;
		if( normalOutFile.size() > 0 )
		{
			int newFile = open(normalOutFile.c_str(), createFlags, S_IRUSR|S_IWUSR);
			if( newFile < 0 )
			{
				fprintf(stderr, "Open out file(%s) open failed (%d:%s)\r\n", normalOutFile.c_str(), errno, strerror(errno));
				fflush(stderr);
				exit(1); // exit forked process.
			}

			lseek(newFile, 0, SEEK_END);
			//close(1); // close stdout
			dup2(newFile, 1);

			if( normalErrFile == normalOutFile )
			{
				appendUsed = true;
				//close(2); // close stderr
				dup2(newFile, 2);
			}
		}

		if( normalErrFile.size() > 0 && !appendUsed )
		{
			int newFile = open(normalErrFile.c_str(), createFlags, S_IRUSR|S_IWUSR);
			
			if( newFile < 0 )
			{
				fprintf(stderr, "Open error file(%s) open failed (%d:%s)\r\n", normalOutFile.c_str(), errno, strerror(errno));
				fflush(stderr);
				exit(1); // exit forked process.
			}

			lseek(newFile, 0, SEEK_END);
			//close(2); // close stderr
			dup2(newFile, 2);
		}

		// close all references of parent file handle
		for( int n = 3; n < 4096; n ++ )
		{
			close(n);
		}
		
		if( normalWorkingPath.size() > 0 )
		{
			if (chdir( normalWorkingPath.c_str() ) < 0)
			{
				fprintf(stderr, "Change working directory to(%s) failed (%d:%s)\r\n", normalWorkingPath.c_str(), errno, strerror(errno));
				fflush(stderr);
				exit(1); // exit forked process.
			}
		}

		int execResult = execvp(normalFile.c_str(), commandArgs);
		if( execResult < 0 )
		{
			fprintf(stderr, "Execv(%s) failed (%d:%s)\r\n", file.c_str(), errno, strerror(errno));
			fflush(stderr);
		}

		exit(0); // exit forked process.
		return 0;
	}
	
	delete []commandArgs;
	commandArgs = NULL;

	int exitCode = 0;
	if( waitMilliSeconds != 0 )
	{
		int64 waitBeginTime = core::common::getHighResolutionTime();
		int64 timeoutTime   = waitBeginTime + int64(waitMilliSeconds) * core::common::kMicroUnitsPerMilli;

		do 
		{
			int waitResult = waitpid(processId, &exitCode, WNOHANG);
			if( waitResult > 0 )
			{
				break;
			}
			core::common::Thread::sleep(100);
		} while ( timeoutTime > core::common::getHighResolutionTime() );
	}

	// wait to prevent child process become an zobime
	waitpid(-1, &exitCode, WNOHANG);

	return processId;
#endif // OS_PLATFORM_WINDOWS
}

bool core::common::Process::terminate( uint32 processId, bool force, uint32 exitCode )
{
#ifdef OS_PLATFORM_WINDOWS
	bool result = false;
	HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, processId);
	if( NULL == process )
	{
		return false;
	}

	result = ::TerminateProcess(process, exitCode) ? true : false;

	// backup error code and restore after CloseHandle
	uint32 nErrorCode = core::common::getErrorCode();
	CloseHandle(process);
	process = NULL;
	core::common::setErrorCode(nErrorCode);

	return result;
#else
	//std::string command = common::String::format("kill %s %u", force ? "-9" : "", processId);
	std::string command = core::common::String::format("kill %s %u >/dev/null 2>/dev/null", force ? "-9" : "", processId);
	int killResult = ::system(command.c_str());

	// wait to prevent child process become an zobime
	int code = 0;
	waitpid((pid_t)processId, &code, WNOHANG);

	return killResult == 0;
#endif
}

bool core::common::Process::terminateAllChilds( uint32 processId, bool force, uint32 exitCode )
{
	int failedCount = 0;
	core::common::ProcessList processList;
	core::common::System::getProcessList(processList);
	std::map<uint32, uint32> parentIdMap;

	for( core::common::ProcessList::iterator itr = processList.begin(); itr != processList.end(); itr ++ )
	{
		core::common::Process &item = (*itr);
		parentIdMap[item.id_] = item.parentId_;
	}

	for( core::common::ProcessList::iterator itr = processList.begin(); itr != processList.end(); itr ++ )
	{
		core::common::Process &item = (*itr);
		int depth = 0;
		uint32 parentId = item.parentId_;
		while( parentId != processId && depth < 20 )
		{
			std::map<uint32, uint32>::iterator itrAncestor = parentIdMap.find(parentId);
			if( itrAncestor == parentIdMap.end() )
			{
				break;
			}
			uint32 ancestorId = itrAncestor->second;
			if( ancestorId == parentId )
			{
				break;
			}
			parentId = ancestorId;
			depth ++;
		}
		if( parentId == processId )
		{
			if( !core::common::Process::terminate(item.id_, force, exitCode) )
			{
				failedCount ++;
			}
		}
	}

	return (0 == failedCount);
}

bool core::common::Process::terminateTree( uint32 processId, bool force, uint32 exitCode )
{
	terminateAllChilds(processId, force, exitCode);

	return core::common::Process::terminate(processId);
}

bool core::common::Process::optimizeAllocateMemory()
{
#if defined(OS_PLATFORM_WINDOWS) || defined(ANDROID)
	// do nothing
#else
	mallopt(M_MMAP_THRESHOLD, 64 * 1024 + 128);
	//mallopt(M_TRIM_THRESHOLD, 1);
#endif
	return true;
}

bool core::common::Process::getAllocateMemory( int64 &systemBytes, int64 &inUsedBytes, int64 &inMMapBytes, int64 &inFastBinBytes )
{
#if defined(OS_PLATFORM_WINDOWS) || defined(ANDROID)
	systemBytes = 0;
	inUsedBytes = 0;
	inMMapBytes = 0;
	inFastBinBytes = 0;
#else
	struct mallinfo mallocInfo = mallinfo();
	systemBytes = (int64)mallocInfo.uordblks;
	inUsedBytes = systemBytes - (int64)mallocInfo.fordblks;
	inMMapBytes = (int64)mallocInfo.hblks;
	inFastBinBytes = (int64)mallocInfo.smblks;
#endif
	return true;
}

//
// class common::SystemProcessor
//
core::common::SystemProcessor::SystemProcessor()
{
	coreCount_  = 1;
	userTime_   = 0;
	niceTime_   = 0;
	systemTime_ = 0;
	idleTime_   = 0;
	ioWaitTime_ = 0;
	irqTime_    = 0;
	softIrqTime_  = 0;
	usagePercent_ = 0;
}

core::common::SystemProcessor::~SystemProcessor()
{
}

int64 core::common::SystemProcessor::getTotalTime()
{
#ifdef OS_PLATFORM_WINDOWS
	return userTime_ + systemTime_;
#else
	return userTime_ + niceTime_ + systemTime_ + idleTime_ + ioWaitTime_ + irqTime_ + softIrqTime_;
#endif
}

int64 core::common::SystemProcessor::getUsageTime()
{
#ifdef OS_PLATFORM_WINDOWS
	return userTime_ + systemTime_ - idleTime_;
#else
	return userTime_ + niceTime_ + systemTime_;
#endif
}

std::string core::common::SystemProcessor::getIdentify()
{
	unsigned long eaxValue = 0, ebxValue = 0, ecxValue = 0, edxValue = 0;
	unsigned long vendorId1 = 0, vendorId2 = 0, vendorId3  = 0;

#if defined(_MSC_VER) // Microsoft Compiler
	_asm 
	{
		mov eax, 0
		cpuid
		mov vendorId1, ebx
		mov vendorId2, edx
		mov vendorId3, ecx

		mov eax, 1
		cpuid
		mov eaxValue, eax
		mov ebxValue, ebx
		mov ecxValue, ecx
		mov edxValue, edx
	}
#elif defined(ARM_LINUX)
	ebxValue = 0;
	asm volatile("mrc p15,0,%0,c0,c0,0":"=r"(eaxValue)::"memory");
#elif defined(MIPSEL_LINUX) || defined(ANDROID)
	ebxValue = 0;
	eaxValue = 0;
	//asm volatile("mrc p15,0,%0,c0,c0,0":"=r"(eaxValue)::"memory");
#else
	#define ASM_CPUID(no,a,b,c,d)  asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (no))

	ASM_CPUID(0, eaxValue, vendorId1, vendorId3, vendorId2);
	ASM_CPUID(1, eaxValue, ebxValue, ecxValue, edxValue);
#endif

	return core::common::String::format("%08lX-%08lX-%08lX-%08lX-%08lX-%08lX", 
		eaxValue, ecxValue, edxValue, vendorId1, vendorId2, vendorId3);
}

//
// class common::System
//

core::common::System::System( bool withProcessors )
{
	withProcessors_ = withProcessors;
	processorList_ = NULL;

#if defined(OS_PLATFORM_WINDOWS)
	if( withProcessors_ )
	{
		HMODULE m_hModule = LoadLibrary("ntdll.dll");
		pfnNtQuerySystemInformation_ = NULL;
		if( m_hModule != NULL )
		{
			pfnNtQuerySystemInformation_ = (PROCNTQSI)GetProcAddress(m_hModule , "NtQuerySystemInformation");
		}
	}
#endif
}

core::common::System::~System()
{
#if defined(OS_PLATFORM_WINDOWS)
	if( module_ != NULL )
	{
		FreeLibrary(module_);
	}	
#endif
	delete processorList_;
	processorList_ = NULL;
}

bool core::common::System::updateProcessor()
{
	SystemProcessor oldProcesser = processor_;
	std::vector<SystemProcessor> oldProcessorList;

	if( withProcessors_ )
	{
		if( processorList_ != NULL )
		{
			oldProcessorList.assign(processorList_->begin() , processorList_->end());
			processorList_->clear();
		}
		else
		{
			processorList_ = new SystemProcessorArray();
		}
	}

#if defined(OS_PLATFORM_WINDOWS)
	SYSTEM_INFO systemInfo;
	GetSystemInfo(&systemInfo);
	processor_.coreCount_ = systemInfo.dwNumberOfProcessors;

	FILETIME idleTime, kernelTime, userTime;
	if( !GetSystemTimes(&idleTime, &kernelTime, &userTime) )
	{
		return false;
	}

	processor_.userTime_    = (int64)((((uint64)userTime.dwHighDateTime) << 32) + (uint64)userTime.dwLowDateTime);
	processor_.systemTime_  = (int64)((((uint64)kernelTime.dwHighDateTime) << 32) + (uint64)kernelTime.dwLowDateTime);
	processor_.idleTime_    = (int64)((((uint64)idleTime.dwHighDateTime) << 32) + (uint64)idleTime.dwLowDateTime);
	processor_.niceTime_    = 0;
	processor_.ioWaitTime_  = 0;
	processor_.irqTime_     = 0;
	processor_.softIrqTime_ = 0;
	
	if( withProcessors_ && NULL != pfnNtQuerySystemInformation_ )
	{		
		ULONG outLength = 0;
		ULONG inBufferLength = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * processor_.coreCount_;

		unsigned char *buffer = (unsigned char*)malloc(inBufferLength);
		DWORD code = (pfnNtQuerySystemInformation_)(SystemProcessorPerformanceInformation , buffer , inBufferLength  , &outLength);
		if( code == 0 )
		{
			SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *info = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*)(buffer);
			for( size_t n = 0 ; n < processor_.coreCount_ ; ++n )
			{
				SystemProcessor processorItem;
				processorItem.idleTime_ = info->IdleTime.QuadPart;
				processorItem.userTime_ = info->UserTime.QuadPart;
				processorItem.systemTime_ = info->KernelTime.QuadPart;
				processorList_->push_back(processorItem);
				++ info;
			}
		}
		free(buffer);
	}

#elif defined(OS_PLATFORM_LINUX)
	core::common::File procFile;

	if( !procFile.open("/proc/stat", core::common::File::kModeRead) )
	{
		return false;
	}

	std::string line;
	core::common::StringArray values;

	if( !procFile.readLine(line, 1024) || core::common::String::split(line, values, ' ', -1, true) < 8 )
	{
		procFile.close();
		return false;
	}

	processor_.userTime_    = core::common::String::parseNumber(values[1], processor_.userTime_);
	processor_.niceTime_    = core::common::String::parseNumber(values[2], processor_.niceTime_);
	processor_.systemTime_  = core::common::String::parseNumber(values[3], processor_.systemTime_);
	processor_.idleTime_    = core::common::String::parseNumber(values[4], processor_.idleTime_);
	processor_.ioWaitTime_  = core::common::String::parseNumber(values[5], processor_.ioWaitTime_);
	processor_.irqTime_     = core::common::String::parseNumber(values[6], processor_.irqTime_);
	processor_.softIrqTime_ = core::common::String::parseNumber(values[7], processor_.softIrqTime_);

	processor_.coreCount_ = 0;
	while( procFile.readLine(line, 1024) )
	{
		if( core::common::String::split(line, values, ' ', -1, true) < 8 )
		{
			break;
		}

		core::common::String::trim(values[0]);
		if( core::common::String::compare(values[0].substr(0, 3), "cpu", true) != 0 )
		{
			break;
		}

		if( withProcessors_ )
		{
			SystemProcessor processorItem;
			processorItem.userTime_    = core::common::String::parseNumber(values[1], processorItem.userTime_);
			processorItem.niceTime_    = core::common::String::parseNumber(values[2], processorItem.niceTime_);
			processorItem.systemTime_  = core::common::String::parseNumber(values[3], processorItem.systemTime_);
			processorItem.idleTime_    = core::common::String::parseNumber(values[4], processorItem.idleTime_);
			processorItem.ioWaitTime_  = core::common::String::parseNumber(values[5], processorItem.ioWaitTime_);
			processorItem.irqTime_     = core::common::String::parseNumber(values[6], processorItem.irqTime_);
			processorItem.softIrqTime_ = core::common::String::parseNumber(values[7], processorItem.softIrqTime_);
			processorList_->push_back(processorItem);
		}

		processor_.coreCount_ ++;
	}

	procFile.close();
#else
#error core::common::System::updateProcessor not implement
#endif

	if( oldProcesser.systemTime_ > 0 )
	{
		// calculate percent
		int64 totalTime1 = oldProcesser.getTotalTime();
		int64 usageTime1 = oldProcesser.getUsageTime();
		int64 totalTime2 = processor_.getTotalTime();
		int64 usageTime2 = processor_.getUsageTime();

		if( totalTime2 > totalTime1 && usageTime2 > usageTime1 )
		{
			processor_.usagePercent_ = double(usageTime2 - usageTime1) / double(totalTime2 - totalTime1) * 100.0;
		}
		else
		{
			processor_.usagePercent_ = 0;
		}
	}
	else
	{
		processor_.usagePercent_ = double(processor_.getUsageTime()) / double(processor_.getTotalTime()) * 100.0;
	}

	if( NULL != processorList_ && oldProcessorList.size() == processor_.coreCount_ )
	{
		for( size_t n = 0 ; n < processor_.coreCount_ ; ++n )
		{
			int64 totalTime1 = oldProcessorList[n].getTotalTime();
			int64 usageTime1 = oldProcessorList[n].getUsageTime();
			int64 totalTime2 = (*processorList_)[n].getTotalTime();
			int64 usageTime2 = (*processorList_)[n].getUsageTime();

			if( totalTime2 > totalTime1 && usageTime2 > usageTime1 )
			{
				(*processorList_)[n].usagePercent_ = double(usageTime2 - usageTime1) / double(totalTime2 - totalTime1) * 100.0;
			}
			else
			{
				(*processorList_)[n].usagePercent_ = 0;
			}
		}
	}

	return true;
}

std::string core::common::System::getHostName()
{
	char hostName[128];
	if( gethostname(hostName, 128) != 0 )
	{
		hostName[0] = '\0';
	}

	return std::string(hostName);
}

std::string core::common::System::getOsVersion()
{
	std::string version;

#if defined(OS_PLATFORM_WINDOWS)
	OSVERSIONINFOEX osvi;
	BOOL osVersionInfoEx = FALSE;
	const DWORD productBufferSize = 1024;

	ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

	if( !(osVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osvi)) )
	{
		osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
		if( !GetVersionEx ( (OSVERSIONINFO *) &osvi) ) 
		{
			return version;
		}
	}

	switch (osvi.dwPlatformId)
	{
		// Test for the Windows NT product family.
	case VER_PLATFORM_WIN32_NT:

		// Test for the specific product.
		if( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2 ) version = "Windows 8 ";
		else if( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1 ) version = "Windows 7 ";
		else if( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0 ) version = "Windows Vista ";
		else if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 ) version = "Windows Server 2003 ";
		else if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 ) version = "Windows XP ";
		else if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 ) version = "Windows 2000 ";
		else version = core::common::String::format("Windows NT(%u.%u)", osvi.dwMajorVersion, osvi.dwMinorVersion);

		// Test for specific product on Windows NT 4.0 SP6 and later.
		if( osVersionInfoEx )
		{
			// Test for the workstation type.
			if ( osvi.wProductType == VER_NT_WORKSTATION )
			{
				if( osvi.dwMajorVersion == 4 )
				{
					version += "Workstation 4.0 ";
				}
				else if (osvi.dwMajorVersion == 6)
				{
					HKEY hKey = NULL;
					LPCSTR lpszKey = "Software\\Microsoft\\Windows NT\\CurrentVersion";
					if( RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpszKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS )
					{
						CHAR szValue[productBufferSize] = {0};
						ULONG ulSize = (ULONG)productBufferSize;
						RegQueryValueExA(hKey, "EditionID", NULL, NULL,(LPBYTE)szValue, &ulSize);
						version += std::string(szValue);
						RegCloseKey(hKey);
					}
				}
				else if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
				{
					version += "Home Edition ";
				}
				else
				{
					version += "Professional ";
				}
			}
			else if ( osvi.wProductType == VER_NT_SERVER || osvi.wProductType == VER_NT_DOMAIN_CONTROLLER )
			{
				if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
				{
					if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) version += "Data Center Edition ";
					else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) version += "Enterprise Edition ";
					else if ( osvi.wSuiteMask == VER_SUITE_BLADE ) version += "Web Edition ";
					else version += "Standard Edition ";
				}
				else if(osvi.dwMajorVersion==5 && osvi.dwMinorVersion==0)
				{
					if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) version += "Data Center Server ";
					else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) version += "Advanced Server ";
					else version += "Server ";
				}
				else  // Windows NT 4.0 
				{
					if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) version += "Server 4.0, Enterprise Edition ";
					else version += "Server 4.0 ";
				}
			}
		}
		// Test for specific product on Windows NT 4.0 SP5 and earlier
		else  
		{
			HKEY hKey = NULL;
			CHAR szProductType[productBufferSize];
			DWORD dwBufLen = productBufferSize;
			LONG lRet = 0;

			memset( szProductType, 0, sizeof(szProductType) );

			if( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE,
				"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
				0, KEY_QUERY_VALUE, &hKey ) )
			{
				if( ERROR_SUCCESS == RegQueryValueExA( hKey, "ProductType", NULL, NULL,
					(LPBYTE) szProductType, &dwBufLen) )
				{
					if( stricmp( "WINNT", szProductType) == 0 ) version += "Workstation ";
					if( stricmp( "LANMANNT", szProductType) == 0 ) version += "Server ";
					if( stricmp( "SERVERNT", szProductType) == 0 ) version += "Advanced Server ";
				}
				RegCloseKey( hKey );
			}

			core::common::String::appendFormat(version, "%u.%u", osvi.dwMajorVersion,  osvi.dwMinorVersion);
		}

		// Display service pack (if any) and build number.
		if( osvi.dwMajorVersion == 4 && 
			stricmp(osvi.szCSDVersion, "Service Pack 6") == 0 )
		{ 
			HKEY hKey = NULL;
			LONG lRet = 0;

			// Test for SP6 versus SP6a.
			if( ERROR_SUCCESS == RegOpenKeyExA( HKEY_LOCAL_MACHINE,
				"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009",
				0, KEY_QUERY_VALUE, &hKey ) )
			{
				core::common::String::appendFormat(version, "Service Pack 6a (Build %d)", osvi.dwBuildNumber & 0xFFFF);
				RegCloseKey( hKey );
			}
			else // Windows NT 4.0 prior to SP6a
			{
				core::common::String::appendFormat(version, "%s (Build %d)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
			}
		}
		else // not Windows NT 4.0 
		{
			core::common::String::appendFormat(version, "%s (Build %d)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
		}
		break;
	}
#elif defined(OS_PLATFORM_LINUX)
	struct utsname unixName;

	memset(&unixName, 0, sizeof(unixName));
	if( uname(&unixName) != 0 )
	{
		version = "Unknown";
	}
	else
	{
		version = core::common::String::format("%s %s %s %s", 
			unixName.sysname, 
			unixName.release,
			unixName.machine,
			unixName.version);
	}
#else
#error "No implement for core::common::System:: getOsVersion() on unknown platform"
#endif

	return version;
}

std::string core::common::System::getOsPlatform()
{
	std::string osPlatform;

#if defined(OS_PLATFORM_WINDOWS)
	osPlatform = "Windows";
#elif defined(OS_PLATFORM_LINUX)
	struct utsname unixName;

	memset(&unixName, 0, sizeof(unixName));
	if( uname(&unixName) != 0 )
	{
		osPlatform = "Unknown";
	}
	else
	{
		std::string hardwarePlatform = unixName.machine;
		if( hardwarePlatform == "i686" )
		{
			hardwarePlatform = "i386";
		}

		osPlatform = core::common::String::format("%s %s", unixName.sysname, hardwarePlatform.c_str());
	}
#else
#error "No implement for core::common::System::getOsPlatform() on unknown platform"
#endif

	core::common::String::replace(osPlatform, " ", "_");
	return osPlatform;
}

bool core::common::System::getPhysicalMemory( core::common::PhysicalMemory &memory )
{
#if defined(OS_PLATFORM_WINDOWS)
	MEMORYSTATUSEX status;
	status.dwLength = sizeof(MEMORYSTATUSEX);

	::GlobalMemoryStatusEx(&status);

	memory.totalBytes_ = status.ullTotalPhys;
	memory.freeBytes_  = status.ullTotalPhys - status.ullAvailPhys;
	memory.availableBytes_ = status.ullAvailPhys;
	memory.cachedBytes_ = 0;
	memory.buffersBytes_ = 0;
#elif defined(OS_PLATFORM_LINUX)
	core::common::File procFile;

	if( !procFile.open("/proc/meminfo", core::common::File::kModeRead) )
	{
		return false;
	}

	std::string line;
	while( procFile.readLine(line, 1024) )
	{
		core::common::StringArray values;
		if( core::common::String::split(line, values, ':', 2) != 2 )
		{
			continue;
		}

		core::common::String::trim(values[0]);
		core::common::String::trim(values[1]);

		const std::string &strKey = values[0];
		const std::string &strValue = values[1];
		if( core::common::String::compare(strKey, "MemTotal", true) == 0 )
		{
			memory.totalBytes_ = core::common::String::parseNumber(strValue, memory.totalBytes_) * core::common::kByteUnitsPerKilo;
		}
		else if( core::common::String::compare(strKey, "MemFree", true) == 0 )
		{
			memory.freeBytes_ = core::common::String::parseNumber(strValue, memory.freeBytes_) * core::common::kByteUnitsPerKilo;
		}
		else if( core::common::String::compare(strKey, "Buffers", true) == 0 )
		{
			memory.buffersBytes_ = core::common::String::parseNumber(strValue, memory.buffersBytes_) * core::common::kByteUnitsPerKilo;
		}
		else if( core::common::String::compare(strKey, "Cached", true) == 0 )
		{
			memory.cachedBytes_ = core::common::String::parseNumber(strValue, memory.cachedBytes_) * core::common::kByteUnitsPerKilo;
		}
	}
	procFile.close();

	memory.availableBytes_ = memory.freeBytes_ + memory.buffersBytes_ + memory.cachedBytes_;
#else
#error core::common::System::getPhysicalMemory not implement
#endif

	if( memory.totalBytes_ > memory.availableBytes_ )
	{
		memory.usagePercent = double(memory.totalBytes_ - memory.availableBytes_) / double(memory.totalBytes_) * 100.0;
	}

	return true;
}

bool core::common::System::getLogicDisk( const std::string &path, core::common::LogicDisk &disk )
{
#if defined(OS_PLATFORM_WINDOWS)
	ULARGE_INTEGER available, total, freeSize;
	if( !GetDiskFreeSpaceExA(path.c_str(), &available, &total, &freeSize) )
	{
		return false;
	}

	disk.totalBytes_     = total.QuadPart;
	disk.freeBytes_      = freeSize.QuadPart;
	disk.availableBytes_ = available.QuadPart;

#elif defined(OS_PLATFORM_LINUX)

#ifndef ANDROID
	struct statvfs diskStat;

	if( statvfs(path.c_str(), &diskStat) != 0 )
	{
		return false;
	}
#else
	struct statfs diskStat;

	if( statfs(path.c_str(), &diskStat) != 0 )
	{
		return false;
	}
#endif

	disk.totalBytes_ = (uint64)(diskStat.f_blocks) * (uint64)(diskStat.f_frsize);
	disk.availableBytes_ = (uint64)(diskStat.f_bavail) * (uint64)(diskStat.f_bsize);
	// default as root
	disk.freeBytes_  = disk.availableBytes_; //(uint64)(diskStat.f_bfree) * (uint64)(diskStat.f_bsize);

#else
#error core::common::System::getLogicDisk not implement
#endif

	if( disk.totalBytes_ > disk.freeBytes_ )
	{
		disk.usagePercent_ = double(disk.totalBytes_ - disk.freeBytes_) / double(disk.totalBytes_) * 100.0;
	}

	return true;
}

time_t core::common::System::getStartupTime( time_t timeNow )
{
	time_t startupTime = 0;

	if( 0 == timeNow )
	{
		timeNow = time(NULL);
	}

#if defined(OS_PLATFORM_WINDOWS)
	LARGE_INTEGER count, freq;
	if( !QueryPerformanceCounter(&count) || !QueryPerformanceFrequency(&freq) ||  0 == freq.QuadPart )
	{
		return 0;
	}

	startupTime = timeNow - (time_t)(count.QuadPart / freq.QuadPart);
#elif defined(OS_PLATFORM_LINUX)
	struct sysinfo info;

	memset(&info, 0, sizeof(info));
	sysinfo(&info);
	startupTime = timeNow - (time_t)info.uptime;
	
	//common::File procFile;

	//if( !procFile.open("/proc/uptime", core::common::File::kModeRead) )
	//{
	//	return 0;
	//}

	//std::string line;
	//common::StringArray values;
	//if( !procFile.ReadLine(line, 1024) || core::common::String::split(line, values, ' ', -1, true) < 1 )
	//{
	//	procFile.close();
	//	return 0;
	//}
	//procFile.close();

	//uint32 timeSecs = core::common::String::ParseNumber(values[0], (uint32)0);
	//startupTime = timeNow - (time_t)timeSecs;
#else
	#error "core::common::System::getStartupTime not implement"
#endif

	return startupTime;
}

bool core::common::System::getCurrentProcess( core::common::Process &process )
{
	char path[core::common::File::kMaxPathLength] = {0};

#if defined(OS_PLATFORM_WINDOWS)

	HANDLE processHandle = ::GetCurrentProcess();
	process.id_ = GetCurrentProcessId();
	process.parentId_ = core::common::Process::kInvalidId;	

	PROCESS_MEMORY_COUNTERS memoryInfo = {0};
	memoryInfo.cb = sizeof(memoryInfo);
	if( GetProcessMemoryInfo(processHandle, &memoryInfo, sizeof(memoryInfo)) )
	{
		process.physicalMemorySize_ = memoryInfo.PeakWorkingSetSize;
		process.virtualMemorySize_  = memoryInfo.WorkingSetSize;
	}

	FILETIME creationTime, exitTime, kernelTime, userTime;	
	if( GetProcessTimes(processHandle , &creationTime , &exitTime , &kernelTime , &userTime) )
	{			
		process.userTime_ = ((uint64)userTime.dwHighDateTime) << 32 | userTime.dwLowDateTime;
		process.kernelTime_ = ((uint64)kernelTime.dwHighDateTime) << 32 | kernelTime.dwLowDateTime;
		process.creationTime_ = ((uint64)creationTime.dwHighDateTime) << 32 | creationTime.dwLowDateTime;
	}

	CloseHandle(processHandle);
#elif defined(OS_PLATFORM_LINUX)

	core::common::File procFile;
	uint32 processId = getpid();
	std::string statName = core::common::String::format("/proc/%d/statm" , processId);
	if( procFile.open(statName, core::common::File::kModeRead) )
	{
		std::string line;
		core::common::StringArray values;
		if( !procFile.readLine(line, 1024) || core::common::String::split(line, values, ' ') < 2 )
		{
			procFile.close();		
		}
		procFile.close();	

		process.parentId_ = 0;
		process.id_ = processId;
		process.threadCount_ = 0;
		process.virtualMemorySize_  = core::common::String::parseNumber(values[0], (uint64)0) * core::common::kMemoryPageSize;
		process.physicalMemorySize_ = core::common::String::parseNumber(values[1], (uint64)0) * core::common::kMemoryPageSize;
	}
	
	statName = core::common::String::format("/proc/%d/cmdline", processId);
	if( procFile.open(statName, core::common::File::kModeRead|core::common::File::kModeBinary) )
	{
		process.commandLine_.resize(core::common::File::kMaxPathLength);
		size_t lineSize = procFile.read((void *)process.commandLine_.c_str(), 1, core::common::File::kMaxPathLength);
		process.commandLine_.resize(lineSize);
	}
	procFile.close();

	statName = core::common::String::format("/proc/%d/stat", processId);
	if( procFile.open(statName, core::common::File::kModeRead|core::common::File::kModeBinary) )
	{
		std::string line;
		core::common::StringArray values;
		if( procFile.readLine(line, 1024) && core::common::String::split(line, values, ' ') != 44 )
		{
			process.userTime_ = core::common::String::parseNumber(values[13] , (uint64)0);
			process.kernelTime_ = core::common::String::parseNumber(values[14] , (uint64)0);
			process.creationTime_ = core::common::String::parseNumber(values[21] , (uint64)0);
		}
	}
	procFile.close();

	statName = core::common::String::format("/proc/%d/exe", processId);
	ssize_t linkLength = readlink(statName.c_str(), path, core::common::File::kMaxPathLength - 1);
	if( linkLength <= 0 || linkLength >= (ssize_t)core::common::File::kMaxPathLength ) path[0] = 0;
	else path[linkLength] = 0;
	process.binaryPath_ = std::string(path);

	statName = core::common::String::format("/proc/%d/cwd", processId);
	linkLength = readlink(statName.c_str(), path, core::common::File::kMaxPathLength - 1);
	if( linkLength <= 0 || linkLength >= (ssize_t)core::common::File::kMaxPathLength ) path[0] = 0;
	else path[linkLength] = 0;
	process.workingPath_ = std::string(path);
#else
#error core::common::System::getCurrentProcess not implement
#endif
	return true;
}

bool core::common::System::getProcessList( core::common::ProcessList &list )
{
	char path[core::common::File::kMaxPathLength] = {0};

#if defined(OS_PLATFORM_WINDOWS)

	HANDLE snapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if( INVALID_HANDLE_VALUE == snapShot )
	{
		return false;
	}

	PROCESSENTRY32 processEntry = {0};
	processEntry.dwSize = sizeof(processEntry);
	if( !Process32First(snapShot, &processEntry) )
	{
		CloseHandle(snapShot);
		return false;
	}

	list.clear();
	do
	{
		HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, processEntry.th32ProcessID);
		if( NULL == processHandle ) continue;

		core::common::Process newProcess;
		newProcess.id_ = (uint32)processEntry.th32ProcessID;
		newProcess.parentId_ = (uint32)processEntry.th32ParentProcessID;
		newProcess.threadCount_ = (uint32)processEntry.cntThreads;

		GetModuleFileNameExA(processHandle, NULL, path, core::common::File::kMaxPathLength);
		path[core::common::File::kMaxPathLength - 1] = 0;
		newProcess.binaryPath_ = std::string(path);

		PROCESS_MEMORY_COUNTERS nMemoryInfo = {0};
		nMemoryInfo.cb = sizeof(nMemoryInfo);
		if( GetProcessMemoryInfo(processHandle, &nMemoryInfo, sizeof(nMemoryInfo)) )
		{
			newProcess.physicalMemorySize_ = nMemoryInfo.PeakWorkingSetSize;
			newProcess.virtualMemorySize_  = nMemoryInfo.WorkingSetSize;
		}

		FILETIME creationTime, exitTime, kernelTime, userTime;	
		if( GetProcessTimes(processHandle , &creationTime , &exitTime , &kernelTime , &userTime) )
		{
			newProcess.userTime_ = ((uint64)userTime.dwHighDateTime) << 32 | userTime.dwLowDateTime;
			newProcess.kernelTime_ = ((uint64)kernelTime.dwHighDateTime) << 32 | kernelTime.dwLowDateTime;
			newProcess.creationTime_ = ((uint64)creationTime.dwHighDateTime) << 32 | creationTime.dwLowDateTime;
		}

		list.push_back(newProcess);
		CloseHandle(processHandle);
	}while( Process32Next(snapShot, &processEntry) );

	CloseHandle(snapShot);

#elif defined(OS_PLATFORM_LINUX)
	const std::string procDirectory = "/proc";
	core::common::FileAttributes files;
	core::common::File::getFileList(procDirectory, files, true);

	for( core::common::FileAttributes::iterator itr = files.begin(); itr != files.end(); itr ++ )
	{
		const std::string &name = itr->first;
		const core::common::FileAttribute &attribute = itr->second;

		if( !attribute.directory_ )
		{
			continue;
		}

		core::common::File procFile;
		std::string statName = core::common::String::format("%s/%s/statm", procDirectory.c_str(), name.c_str());
		if( !procFile.open(statName, core::common::File::kModeRead) )
		{
			continue;
		}

		std::string line;
		core::common::StringArray values;
		if( !procFile.readLine(line, 1024) || core::common::String::split(line, values, ' ') < 2 )
		{
			procFile.close();
			continue;
		}
		procFile.close();

		core::common::Process newProcess;
		newProcess.id_ = core::common::String::parseNumber(name, (uint32)0);
		newProcess.parentId_ = 0;
		newProcess.threadCount_ = 0;
		newProcess.virtualMemorySize_  = core::common::String::parseNumber(values[0], (uint64)0) * core::common::kMemoryPageSize;
		newProcess.physicalMemorySize_ = core::common::String::parseNumber(values[1], (uint64)0) * core::common::kMemoryPageSize;

		statName = core::common::String::format("%s/%s/exe", procDirectory.c_str(), name.c_str());
		ssize_t nLinkLen = readlink(statName.c_str(), path, core::common::File::kMaxPathLength - 1);
		if( nLinkLen <= 0 || nLinkLen >= (ssize_t)core::common::File::kMaxPathLength ) path[0] = 0;
		else path[nLinkLen] = 0;
		newProcess.binaryPath_ = std::string(path);

		statName = core::common::String::format("%s/%s/cwd", procDirectory.c_str(), name.c_str());
		nLinkLen = readlink(statName.c_str(), path, core::common::File::kMaxPathLength - 1);
		if( nLinkLen <= 0 || nLinkLen >= (ssize_t)core::common::File::kMaxPathLength ) path[0] = 0;
		else path[nLinkLen] = 0;
		newProcess.workingPath_ = std::string(path);

		statName = core::common::String::format("%s/%s/cmdline", procDirectory.c_str(), name.c_str());
		if( procFile.open(statName, core::common::File::kModeRead|core::common::File::kModeBinary) )
		{
			newProcess.commandLine_.resize(core::common::File::kMaxPathLength);
			size_t lineSize = procFile.read((void *)newProcess.commandLine_.c_str(), 1, core::common::File::kMaxPathLength);
			newProcess.commandLine_.resize(lineSize);
		}

		list.push_back(newProcess);
	}
#else
#error core::common::System::getProcessList not implement
#endif

	return true;
}

bool core::common::System::checkSystemUser( const std::string &user, const std::string &password )
{
#if defined(OS_PLATFORM_WINDOWS)

	DWORD   dwLogonType = LOGON32_LOGON_NETWORK;
	DWORD   dwLogonPro  = LOGON32_PROVIDER_DEFAULT;
	HANDLE  hToken = INVALID_HANDLE_VALUE;
	if ( LogonUser(user.c_str(), NULL, password.c_str(), dwLogonType, dwLogonPro, &hToken) )
	{
		CloseHandle(hToken);
		return true;
	}

#elif defined(OS_PLATFORM_LINUX)

#ifndef ANDROID
	struct spwd *pwd = getspnam(user.c_str());
	if(pwd == NULL)
	{
		return false;
	}

	char *cryptData = crypt(password.c_str(), pwd->sp_pwdp);
	if (cryptData == NULL)
	{
		return false;
	}

	if(strcmp(pwd->sp_pwdp, cryptData) == 0)
	{
		return true;
	}
#endif

#endif

	return false;
}

#if defined(OS_PLATFORM_WINDOWS)
wchar_t *__winStlString2WideChar( const std::string &data )
{
	int bufferSize = MultiByteToWideChar(GetACP(), 0, data.c_str(), -1, NULL, 0); 
	wchar_t *newChar = new wchar_t[bufferSize + 1];
	ZeroMemory(newChar, sizeof(wchar_t) * (bufferSize + 1));
	MultiByteToWideChar(GetACP(), 0, data.c_str(), -1, newChar, bufferSize);

	return newChar;
}
#endif

bool core::common::System::changeSystemPassword( const std::string &username, const std::string &oldPassword, const std::string &newPassword )
{
	bool result = false;

#if defined(OS_PLATFORM_WINDOWS)
	NET_API_STATUS status = 0;
	wchar_t *pUsername = __winStlString2WideChar(username);
	wchar_t *pOldPassword = __winStlString2WideChar(oldPassword);
	wchar_t *pNewPassword = __winStlString2WideChar(newPassword);
	status = NetUserChangePassword(NULL, pUsername, pOldPassword, pNewPassword);
	if ( status != NERR_Success )
	{
		__ULOG_ERROR(__ULOG_FMT_ERR("common::System", "Change system user's(%s) failed,old password(%s), new password(%s)"),
			username.c_str(),oldPassword.c_str(),newPassword.c_str(),__UERR_CODE,__UERR_STR);
	}
	else
	{
		result = true;
	}

	delete []pUsername;
	delete []pOldPassword;
	delete []pNewPassword;
	pUsername = NULL;
	pOldPassword = NULL;
	pNewPassword = NULL;

#elif defined(OS_PLATFORM_LINUX) && !defined(ANDROID)

	std::string pwdPath = "/etc/shadow";
	char *cryptPwd = NULL;
	FILE *fileShadow = NULL;
	//std::string salt;

	do 
	{
		struct spwd *shadowPwd = getspnam(username.c_str());
		if ( NULL == shadowPwd )
		{
			__ULOG_ERROR(__ULOG_FMT_ERR("common::System", "Get (%s) from shadow to change password failed"), username.c_str(),__UERR_CODE,__UERR_STR);
			break;
		}

		cryptPwd = crypt(newPassword.c_str(), shadowPwd->sp_pwdp);
		if( NULL == cryptPwd )
		{
			__ULOG_ERROR(__ULOG_FMT_ERR("common::System", "Crypt (%s) new password failed"), username.c_str(),__UERR_CODE,__UERR_STR);
			break;
		}

		shadowPwd->sp_pwdp = cryptPwd;
		fileShadow = fopen(pwdPath.c_str(), "r+");
		if ( NULL == fileShadow )
		{
			__ULOG_ERROR(__ULOG_FMT_ERR("common::System", "Open file(%s) to change password failed"),pwdPath.c_str(),__UERR_CODE,__UERR_STR);
			break;
		}

		if( putspent(shadowPwd, fileShadow) != 0 )
		{
			__ULOG_ERROR(__ULOG_FMT_ERR("common::System", "Put password to shadow failed"),__UERR_CODE,__UERR_STR);
			break;
		}

		result = true;
	} while (false);

	if( NULL != fileShadow )
	{
		fclose(fileShadow);
		fileShadow = NULL;
	}
#endif

	return result;
}

bool core::common::System::rebootSystem()
{
#if defined(OS_PLATFORM_WINDOWS)
	HANDLE process = ::GetCurrentProcess(); 
	HANDLE token = NULL; 
	LUID uid = {0}; 
	TOKEN_PRIVILEGES tokenPrivileges = {0}; 

	if( !::OpenProcessToken(process,TOKEN_ADJUST_PRIVILEGES,&token) )
	{
		__ULOG_ERROR(__ULOG_FMT_ERR("common::Reboot", "Open process token failed"), __UERR_CODE, __UERR_STR);
		return false;
	}

	if( !::LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&uid) )
	{
		__ULOG_ERROR(__ULOG_FMT_ERR("common::Reboot", "Lookup privilege value failed"), __UERR_CODE, __UERR_STR);
		return false;
	}

	tokenPrivileges.PrivilegeCount = 1;
	tokenPrivileges.Privileges[0].Luid = uid;
	tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	if( !::AdjustTokenPrivileges(token,FALSE,&tokenPrivileges,sizeof tokenPrivileges,NULL,NULL) )
	{
		__ULOG_ERROR(__ULOG_FMT_ERR("common::Reboot", "Adjust token privilege failed"), __UERR_CODE, __UERR_STR);
		return false; 
	}

	if( ::GetLastError() != ERROR_SUCCESS )
	{
		__ULOG_ERROR(__ULOG_FMT_ERR("common::Reboot", "Get last error failed"), __UERR_CODE, __UERR_STR);
		return false;
	}

	::CloseHandle(token);

	__ULOG_INFO(__ULOG_FMT("common::Reboot", "Start to reboot system"));
	return ExitWindowsEx(EWX_REBOOT, EWX_FORCE) == TRUE;
#elif defined(OS_PLATFORM_LINUX)
	__ULOG_INFO(__ULOG_FMT("common::Reboot", "Start to reboot system"));
	return reboot(LINUX_REBOOT_CMD_RESTART) == 0;
#endif
}

bool core::common::System::getPhysicalDiskList( core::common::PhysicalDiskArray &diskes, core::common::PhysicalPartitionArray &partitions )
{
	diskes.clear();
	partitions.clear();

#if defined(OS_PLATFORM_WINDOWS)
	for( int idx = 0; idx < 100; idx ++ )
	{
		std::string physicalDriver = core::common::String::format("\\\\.\\PhysicalDrive%d" , idx);
		HANDLE device = CreateFileA(physicalDriver.c_str() , GENERIC_READ|GENERIC_WRITE , FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
		if( device == INVALID_HANDLE_VALUE )
		{
			break;
		}

		GET_LENGTH_INFORMATION infoStruct;
		DWORD bytesOutput = 0;
		ZeroMemory(&infoStruct, sizeof(infoStruct));
		if( !DeviceIoControl(device, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &infoStruct, sizeof(infoStruct), &bytesOutput, NULL) )
		{
			continue;
		}
		
		core::common::PhysicalDisk disk;
		disk.totalBytes_ = infoStruct.Length.QuadPart;
		disk.description = core::common::String::format("HDD_%d" , idx);
		diskes.push_back(disk);
		CloseHandle(device);
	}

	int partitionCount = 0;
	DWORD code = GetLogicalDriveStringsA(0 , NULL);
	char *buffer = (char *)malloc(sizeof(char) * code + 1);
	memset(buffer , 0 , code + 1);
	code = GetLogicalDriveStringsA(code + 1 , buffer);
	for( char *tmp = buffer ; *tmp && partitionCount < 100; tmp += strlen(tmp) + 1, partitionCount ++ )
	{		
		std::string root = tmp;
		if( GetDriveTypeA(root.c_str()) != DRIVE_FIXED )
		{
			continue;
		}

		ULARGE_INTEGER availableSize, totalSize, freeSize;
		if( !GetDiskFreeSpaceExA(root.c_str(), &availableSize, &totalSize, &freeSize) )
		{
			break;
		}

		PhysicalPartition partition;
		partition.totalBytes_     = totalSize.QuadPart;
		partition.freeBytes_      = freeSize.QuadPart;
		partition.availableBytes_ = availableSize.QuadPart;
		partition.description     = root;
		if( partition.totalBytes_ > partition.freeBytes_ )
		{
			partition.usagePercent_ = double(partition.totalBytes_ - partition.freeBytes_) / double(partition.totalBytes_) * 100.0;
		}
		partitions.push_back(partition);
	}

#elif defined (OS_PLATFORM_LINUX)
	core::common::File diskFile;
	if (!diskFile.open("/etc/mtab",core::common::File::kModeRead) )
	{
		return false;
	}

	std::string line;
	PhysicalDisk disk;
	PhysicalPartition partition;
	while( diskFile.readLine(line, 1024) )
	{
		core::common::StringArray values;
		if( core::common::String::split(line, values, " ", 6) != 6 )
		{
			continue;
		}
		if( strstr(values[0].c_str() ,"/dev") == NULL )
		{
			continue;
		}
			
		struct statfs diskStatfs;
		std::string mountPoint = values[1];
		if( ::statfs(mountPoint.c_str() , &diskStatfs) < 0 )
		{
			return false;
		}

		partition.totalBytes_     = diskStatfs.f_blocks * diskStatfs.f_bsize;
		partition.freeBytes_      = diskStatfs.f_bfree * diskStatfs.f_bsize;
		partition.availableBytes_ = diskStatfs.f_bavail * diskStatfs.f_bsize;
		partition.description     = mountPoint;
		if( partition.totalBytes_ > partition.freeBytes_ )
		{
			partition.usagePercent_ = double(partition.totalBytes_ - partition.freeBytes_) / double(partition.totalBytes_) * 100.0;
		}
		partitions.push_back(partition);
		disk.totalBytes_ += partition.totalBytes_;
	}
	diskes.push_back(disk);
	diskFile.close();
#endif
	return true;
}
